#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

#define NUM 1024 // 一个指令的最大长度
#define OPT_NUM 64  // 一个指令的最多选项

char lineCommand[NUM];  // 保存输入命令的数组
char* myargv[OPT_NUM];  // 保存选项的数组

int  lastCode = 0; // 保存退出码
int  lastSig = 0; //保存退出信号

int main()
{
    while(1)
    {
        // 输出提示符
    	printf("[用户名@主机名 当前路径]$ ");
    	fflush(stdout);
    
    	// 从键盘(stdin)获取指令输入
    	char* s = fgets(lineCommand,sizeof(lineCommand)-1,stdin);//最后一个位置来保存极端场景下的\0
    	if(s == NULL)
    	{
        	perror("fgets");
        	exit(1);
    	}
    
    	lineCommand[strlen(lineCommand)-1] = '\0', //消除命令行中最后的换行符
    
    	// 将输入的字符串解析为说个字符串存放到myargv数组中，即字符串切割
    	myargv[0] = strtok(lineCommand, " ");
        int i = 1;
        if(myargv[0] != NULL && strcmp(myargv[0],"ls") == 0)
        {
            myargv[i++] = (char*)"--color=auto";
        }
        while(myargv[i++] = strtok(NULL, " "));

        // cd 父进程的路径
        if(myargv[0] != NULL && strcmp(myargv[0],"cd") == 0)
        {
            if(myargv[1] != NULL)
            {
                 chdir(myargv[1]);// myargv[1]中保存着指定路径
            }
            continue;  // 下面的语句不需要在继续执行了，以为你cd的目的已经达到了
        }
        if(myargv[0] != NULL && myargv[1] != NULL && strcmp(myargv[0], "echo") == 0)
		{
    		if(strcmp(myargv[1], "$?") == 0)
    		{
        		printf("%d, %d\n", lastCode, lastSig);
   			}
    		else
    		{
        		printf("%s\n", myargv[1]);
    		}
    		continue;
		}

    	// 创建子进程
    	pid_t id = fork();
    
    	if(id == -1)
    	{
        	perror("fork");
        	exit(1);
    	}
    	else if(id == 0)
    	{
        	// 子进程进行进程程序替换
        	execvp(myargv[0],myargv);
        	exit(1);
    	}
        else
        {
            int status = 0;
    	    pid_t ret = waitpid(id, &status,0);
    
    	    if(ret == -1)
    	    {
        	    perror("waitpid");
        	    exit(1);
    	    }
			lastCode = ((status >> 8) & 0xff);
            lastSig = (status & 0x7f);
        }
    }
   	
    return 0;
}
